home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The CICA Windows Explosion!
/
The CICA Windows Explosion! - Disc 1.iso
/
desktop
/
dibquant.zip
/
DIBQUANT.C
next >
Wrap
C/C++ Source or Header
|
1994-06-17
|
24KB
|
864 lines
///////////////////////////////////////////////////////////////////////////
// DIBQuant version 1.0
// Copyright (c) 1993 Edward McCreary.
// All rights reserved.
//
// Redistribution and use in source and binary forms are freely permitted
// provided that the above copyright notice and attibution and date of work
// and this paragraph are duplicated in all such forms.
// THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
// WARRANTIES OF MERCHANTIBILILTY AND FITNESS FOR A PARTICULAR PURPOSE.
///////////////////////////////////////////////////////////////////////////
#define STRICT
#include <windows.h>
#include <windowsx.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include "dibquant.h"
#include "rgbvtab.h"
#include "local.h"
#include "palette.h"
///////////////////////////////////////////////////////////////////////////
// ordered dither matrix
int ord_dith[4][4] = {{-7, 1, -5, 3},
{ 5, -3, 7, -1},
{-4, 4, -6, 2},
{ 8, 0, 6, -2}};
// instance handle of dll
HINSTANCE hInst;
///////////////////////////////////////////////////////////////////////////
// Main DLL Entry Point
BOOL WINAPI LibMain (HINSTANCE hInstance, WORD wDataSeg,
WORD wHeapSize, LPSTR lpszCmdLine)
{
if(wHeapSize != 0)
UnlockData(0);
hInst = hInstance;
return (TRUE);
}
///////////////////////////////////////////////////////////////////////////
// Exit procedure for DLL
int WINAPI WEP(int nSystemExit)
{
switch(nSystemExit)
{
case WEP_SYSTEM_EXIT:
break;
case WEP_FREE_DLL:
break;
}
return (1);
}
///////////////////////////////////////////////////////////////////////////
// build buffer space and lookup table
LPQUANT_BUFFER InitLUT()
{
LPQUANT_BUFFER lpBuffer;
unsigned long i;
unsigned long len;
lpBuffer = (LPQUANT_BUFFER)malloc(sizeof(QUANT_BUFFER));
if(!lpBuffer)
return NULL;
// lut for x^2
for(i=0;i<256;i++)
lpBuffer->SQR[i] = (long)i*(long)i;
len = (long)COLOR_MAX*(long)COLOR_MAX*(long)COLOR_MAX;
// buffer to store every color in image
lpBuffer->lpHisto = (LPNode huge *)GlobalAllocPtr(GHND,len*sizeof(LPNode));
return lpBuffer;
}
///////////////////////////////////////////////////////////////////////////
// free memory associated with buffers and luts
void ClearLUT(LPQUANT_BUFFER lpBuffers)
{
unsigned long len = (long)COLOR_MAX*(long)COLOR_MAX*(long)COLOR_MAX;
unsigned long i;
if(lpBuffers->lpHisto)
{
for(i=0;i<len;i++)
if(lpBuffers->lpHisto[i] != NULL)
{
free(lpBuffers->lpHisto[i]);
lpBuffers->lpHisto[i] = NULL;
}
GlobalFreePtr((LPSTR)lpBuffers->lpHisto);
}
free(lpBuffers);
}
///////////////////////////////////////////////////////////////////////////
// main procedures, quantize 24-bit dib
LPSTR FAR PASCAL __export QuantizeDIB(LPSTR lpDIB, int nPalette, int nDither,FARPROC lpStatus)
{
long width,height;
LPBITMAPINFOHEADER lpbmi;
LPSTR lpData;
BYTE huge *lpLine;
long i,j;
int r,g,b;
long dib_width;
LPSTR lpNewDIB;
char buffer[80];
LPQUANT_BUFFER lpBuffer;
// must have adib
if(!lpDIB)
return NULL;
// must be a 24-bit dib
lpbmi = (LPBITMAPINFOHEADER)lpDIB;
if(lpbmi->biBitCount != 24)
return NULL;
// allocate buffers
lpBuffer = InitLUT();
if(!lpBuffer)
return NULL;
// store handle to status indicator callback
lpBuffer->lpStatus = lpStatus;
width = lpbmi->biWidth;
height = lpbmi->biHeight;
dib_width = WIDTHBYTES(24*width);
lpData = FindDIBBits(lpDIB);
// generate list of all colors if needed
if(nPalette != IDX_DEFAULT)
for(j=0;j<height;j++)
{
lpLine = (BYTE huge *)lpData + dib_width*j;
i = width;
if(lpBuffer->lpStatus)
{
wsprintf(buffer,"Finding all colors, %d%%",(int)(100.0*((float)j/(float)height)));
((STATUS_CAST)lpBuffer->lpStatus)(buffer);
}
while(i--)
{
b = (int)*lpLine++;
g = (int)*lpLine++;
r = (int)*lpLine++;
add_color(r>>3,g>>3,b>>3,1L,lpBuffer);
}
}
// call status if needed
if(lpBuffer->lpStatus)
((STATUS_CAST)lpBuffer->lpStatus)("Building new palette...");
switch(nPalette)
{
case IDX_MEDIAN:
m_box(lpBuffer);
break;
case IDX_POPULARITY:
pop(lpBuffer);
break;
case IDX_DEFAULT:
LoadDefaultPal(lpBuffer);
break;
default:
m_box(lpBuffer);
break;
}
lpNewDIB = Dither(lpDIB,nDither,lpBuffer);
ClearLUT(lpBuffer);
return lpNewDIB;
}
///////////////////////////////////////////////////////////////////////////
// dither image
LPSTR __export Dither(LPSTR lpDIB,int nDither,LPQUANT_BUFFER lpBuffer)
{
LPSTR lpNewDIB;
LPSTR lpSrcData;
LPSTR lpDestData;
long src_dib_width,dest_dib_width;
LPBITMAPINFOHEADER lpbmih;
long width,height;
BYTE huge *lpSrcLine;
BYTE huge *lpDestLine;
long i,j;
char buffer[80];
int r,g,b;
lpNewDIB = AllocNewDIB(lpDIB,lpBuffer);
if(!lpNewDIB)
return NULL;
lpSrcData = FindDIBBits(lpDIB);
lpDestData = FindDIBBits(lpNewDIB);
lpbmih = (LPBITMAPINFOHEADER)lpDIB;
if(lpbmih->biBitCount != 24)
return NULL;
width = lpbmih->biWidth;
height = lpbmih->biHeight;
src_dib_width = WIDTHBYTES(24*width);
dest_dib_width = WIDTHBYTES(8*width);
for(j=0;j<height;j++)
{
lpSrcLine = (BYTE huge *)lpSrcData + src_dib_width*j;
lpDestLine = (BYTE huge *)lpDestData + dest_dib_width*j;
if(lpBuffer->lpStatus)
{
wsprintf(buffer,"Building new Image, %d%%",(int)(100.0*((float)j/(float)height)));
((STATUS_CAST)lpBuffer->lpStatus)(buffer);
}
i = width;
while(i--)
{
b = (int)*lpSrcLine++;
g = (int)*lpSrcLine++;
r = (int)*lpSrcLine++;
if(nDither == IDX_JITTER)
jitter(i,j,&r,&g,&b);
if(nDither == IDX_ORDERED)
{
r += 2*ord_dith[i%4][j%4]; r = CLIP(r);
g += 2*ord_dith[i%4][j%4]; g = CLIP(g);
b += 2*ord_dith[i%4][j%4]; b = CLIP(b);
}
*lpDestLine++ = (BYTE)GetNeighbor(r,g,b,lpBuffer);
}
}
if(lpBuffer->lpStatus)
{
wsprintf(buffer,"Building new Image, 100%%");
((STATUS_CAST)lpBuffer->lpStatus)(buffer);
}
return lpNewDIB;
}
///////////////////////////////////////////////////////////////////////////
// build new palette with median cut algorithm
// I didn't write this, if you know who did, please let me know!
void __export m_box(LPQUANT_BUFFER lpBuffer)
{
int i, j, max, dr, dg, db;
char buffer[80];
/* force the counts in the corners to be zero */
force( 0, 0, 0, 0L,lpBuffer);
force(COLOR_MAX-1, 0, 0, 0L,lpBuffer);
force( 0, COLOR_MAX-1, 0, 0L,lpBuffer);
force( 0, 0, COLOR_MAX-1, 0L,lpBuffer);
force(COLOR_MAX-1, COLOR_MAX-1, 0, 0L,lpBuffer);
force( 0, COLOR_MAX-1, COLOR_MAX-1, 0L,lpBuffer);
force(COLOR_MAX-1, 0, COLOR_MAX-1, 0L,lpBuffer);
force(COLOR_MAX-1, COLOR_MAX-1, COLOR_MAX-1, 0L,lpBuffer);
/* assign the 1st eight boxes to be the corners */
make_box( 0, 0, 0, 0, 1L,lpBuffer);
make_box(COLOR_MAX-1, 0, 0, 1, 1L,lpBuffer);
make_box( 0, COLOR_MAX-1, 0, 2, 1L,lpBuffer);
make_box( 0, 0, COLOR_MAX-1, 3, 1L,lpBuffer);
make_box(COLOR_MAX-1, COLOR_MAX-1, 0, 4, 1L,lpBuffer);
make_box( 0, COLOR_MAX-1, COLOR_MAX-1, 5, 1L,lpBuffer);
make_box(COLOR_MAX-1, 0, COLOR_MAX-1, 6, 1L,lpBuffer);
make_box(COLOR_MAX-1, COLOR_MAX-1, COLOR_MAX-1, 7, 1L,lpBuffer);
/* set up 9th box to hold the rest of the world */
lpBuffer->box[8].r0 = 0;
lpBuffer->box[8].r1 = COLOR_MAX-1;
lpBuffer->box[8].g0 = 0;
lpBuffer->box[8].g1 = COLOR_MAX-1;
lpBuffer->box[8].b0 = 0;
lpBuffer->box[8].b1 = COLOR_MAX-1;
squeeze(8,lpBuffer);
/* split the rest of the boxes */
for(i=9; i<256; i++)
{
if(lpBuffer->lpStatus)
{
wsprintf(buffer,"splitting box %d",i);
((STATUS_CAST)lpBuffer->lpStatus)(buffer);
}
/* find biggest box */
max = 8;
for(j=8; j<i; j++)
if(lpBuffer->box[j].count > lpBuffer->box[max].count)
max = j;
/* decide which side to split the box along, and split it */
dr = lpBuffer->box[max].r1 - lpBuffer->box[max].r0;
dg = lpBuffer->box[max].g1 - lpBuffer->box[max].g0;
db = lpBuffer->box[max].b1 - lpBuffer->box[max].b0;
lpBuffer->box[i] = lpBuffer->box[max]; /* copy info over */
if(dr>=dg && dr>=db)
{ /* red! */
if(dr==2)
{ /* tight squeeze */
lpBuffer->box[i].r1 = lpBuffer->box[i].r0;
lpBuffer->box[max].r0 = lpBuffer->box[max].r1;
} else
{ /* figure out where to split */
j = lpBuffer->box[max].rave;
if(j==lpBuffer->box[max].r1)
j--;
lpBuffer->box[max].r1 = j;
lpBuffer->box[i].r0 = j+1;
}
squeeze(i,lpBuffer);
squeeze(max,lpBuffer);
}
else if(dg>=db)
{ /* green! */
if(dg==2)
{ /* tight squeeze */
lpBuffer->box[i].g1 = lpBuffer->box[i].g0;
lpBuffer->box[max].g0 = lpBuffer->box[max].g1;
}
else
{ /* figure out where to split */
j = lpBuffer->box[max].gave;
if(j==lpBuffer->box[max].g1)
j--;
lpBuffer->box[max].g1 = j;
lpBuffer->box[i].g0 = j+1;
}
squeeze(i,lpBuffer);
squeeze(max,lpBuffer);
}
else
{ /* blue! */
if(db==2)
{ /* tight squeeze */
lpBuffer->box[i].b1 = lpBuffer->box[i].b0;
lpBuffer->box[max].b0 = lpBuffer->box[max].b1;
}
else
{ /* figure out where to split */
j = lpBuffer->box[max].bave;
if(j==lpBuffer->box[max].b1)
j--;
lpBuffer->box[max].b1 = j;
lpBuffer->box[i].b0 = j+1;
}
squeeze(i,lpBuffer);
squeeze(max,lpBuffer);
}
} /* end of i loop, all the boxes are found */
/* get palette colors for each box */
for(i=0; i<256; i++)
{
lpBuffer->red[i] = (lpBuffer->box[i].r0+lpBuffer->box[i].r1)/2;
lpBuffer->green[i] = (lpBuffer->box[i].g0+lpBuffer->box[i].g1)/2;
lpBuffer->blue[i] = (lpBuffer->box[i].b0+lpBuffer->box[i].b1)/2;
}
for(i=0; i<256; i++)
{
lpBuffer->red[i] *= 255;
lpBuffer->red[i] /= (COLOR_MAX-1);
lpBuffer->green[i] *= 255;
lpBuffer->green[i] /= (COLOR_MAX-1);
lpBuffer->blue[i] *= 255;
lpBuffer->blue[i] /= (COLOR_MAX-1);
}
} /* end of m_box() */
///////////////////////////////////////////////////////////////////////////
// make a 1x1x1 box at index with color rgb count c
void make_box(int r, int g, int b, int index, unsigned long c,LPQUANT_BUFFER lpBuffer)
{
lpBuffer->box[index].r0 = r;
lpBuffer->box[index].r1 = r;
lpBuffer->box[index].g0 = g;
lpBuffer->box[index].g1 = g;
lpBuffer->box[index].b0 = b;
lpBuffer->box[index].b1 = b;
lpBuffer->box[index].count = c;
} /* end of make_box
/*
squeeze -- shrink a boxes extremes to fit tightly
if a box is 1x1x1 change its count to 1
*/
///////////////////////////////////////////////////////////////////////////
//
void squeeze(int b,LPQUANT_BUFFER lpBuffer)
{
int r0, r1, g0, g1, b0, b1;
long i, j, k;
unsigned long count = 0;
LPNode ptr;
DWORD index;
r0 = lpBuffer->box[b].r0;
r1 = lpBuffer->box[b].r1;
g0 = lpBuffer->box[b].g0;
g1 = lpBuffer->box[b].g1;
b0 = lpBuffer->box[b].b0;
b1 = lpBuffer->box[b].b1;
lpBuffer->box[b].r0 = COLOR_MAX-1; lpBuffer->box[b].r1 = 0;
lpBuffer->box[b].g0 = COLOR_MAX-1; lpBuffer->box[b].g1 = 0;
lpBuffer->box[b].b0 = COLOR_MAX-1; lpBuffer->box[b].b1 = 0;
lpBuffer->box[b].rave = 0;
lpBuffer->box[b].gave = 0;
lpBuffer->box[b].bave = 0;
for(i=r0; i<=r1; i++)
for(j=g0; j<=g1; j++)
for(k=b0; k<=b1; k++)
{
index = INDEX(i,j,k);
ptr = lpBuffer->lpHisto[index];
if(ptr)
if(ptr->count>0L)
{
lpBuffer->box[b].r0 = MIN(i, lpBuffer->box[b].r0);
lpBuffer->box[b].r1 = MAX(i, lpBuffer->box[b].r1);
lpBuffer->box[b].g0 = MIN(j, lpBuffer->box[b].g0);
lpBuffer->box[b].g1 = MAX(j, lpBuffer->box[b].g1);
lpBuffer->box[b].b0 = MIN(k, lpBuffer->box[b].b0);
lpBuffer->box[b].b1 = MAX(k, lpBuffer->box[b].b1);
lpBuffer->box[b].rave += (unsigned long)i * (unsigned long)ptr->count;
lpBuffer->box[b].gave += (unsigned long)j * (unsigned long)ptr->count;
lpBuffer->box[b].bave += (unsigned long)k * (unsigned long)ptr->count;
count += (unsigned long)ptr->count;
}
}
/* box is now shrunk */
if(count)
{
lpBuffer->box[b].rave /= count;
lpBuffer->box[b].gave /= count;
lpBuffer->box[b].bave /= count;
}
lpBuffer->box[b].count = MIN(count, COUNT_LIMIT);
if(lpBuffer->box[b].r0 == lpBuffer->box[b].r1 &&
lpBuffer->box[b].g0 == lpBuffer->box[b].g1 &&
lpBuffer->box[b].b0 == lpBuffer->box[b].b1)
{ /* box is min size */
lpBuffer->box[b].count = 1L; /* so it won't get split again */
}
} /* end of squeeze */
///////////////////////////////////////////////////////////////////////////
//
void add_color(int r, int g, int b, unsigned long c,LPQUANT_BUFFER lpBuffer)
{
LPNode ptr;
unsigned long ltmp;
DWORD index = INDEX(r,g,b);
c = MIN(c,COUNT_LIMIT);
if((ptr = lpBuffer->lpHisto[index]) == NULL) // new color
{
ptr = lpBuffer->lpHisto[index] = (Node *)malloc(sizeof(Node));
ptr->index = -1;
ptr->count = c;
}
else
{
ltmp = ptr->count;
ltmp += c;
ptr->count = MIN(ltmp,COUNT_LIMIT);
}
} /* end of add_color()*/
///////////////////////////////////////////////////////////////////////////
//
void force(int r, int g, int b, unsigned long c,LPQUANT_BUFFER lpBuffer)
{
LPNode ptr;
DWORD index;
c = MIN(c,COUNT_LIMIT);
index = INDEX(r,g,b);
if((ptr = lpBuffer->lpHisto[index]) == NULL) // new color
{
ptr = lpBuffer->lpHisto[index] = (Node *)malloc(sizeof(Node));
ptr->index = -1;
ptr->count = 0L;
}
ptr->count = c;
} /* end of force()*/
///////////////////////////////////////////////////////////////////////////
// popularity sort
void pop(LPQUANT_BUFFER lpBuffer)
{
int i, r, g,b;
LPNode ptr;
unsigned long pal[256];
DWORD index;
DWORD index_cache = (DWORD)-1;
LPNode ptr_cache;
memset(pal,0,sizeof(unsigned long)*256);
/* force corners of rgb color cube out of the running */
add_color( 0, 0, 0, 0L,lpBuffer);
add_color(COLOR_MAX-1, 0, 0, 0L,lpBuffer);
add_color( 0, COLOR_MAX-1, 0, 0L,lpBuffer);
add_color( 0, 0, COLOR_MAX-1, 0L,lpBuffer);
add_color(COLOR_MAX-1, COLOR_MAX-1, 0, 0L,lpBuffer);
add_color( 0, COLOR_MAX-1, COLOR_MAX-1, 0L,lpBuffer);
add_color(COLOR_MAX-1, 0, COLOR_MAX-1, 0L,lpBuffer);
add_color(COLOR_MAX-1, COLOR_MAX-1, COLOR_MAX-1, 0L,lpBuffer);
/* force feed the corners into the palette */
lpBuffer->red[0] = 0; lpBuffer->green[0] = 0; lpBuffer->blue[0] = 0;
lpBuffer->red[1] = COLOR_MAX-1; lpBuffer->green[1] = 0; lpBuffer->blue[1] = 0;
lpBuffer->red[2] = 0; lpBuffer->green[2] = COLOR_MAX-1; lpBuffer->blue[2] = 0;
lpBuffer->red[3] = 0; lpBuffer->green[3] = 0; lpBuffer->blue[3] = COLOR_MAX-1;
lpBuffer->red[4] = COLOR_MAX-1; lpBuffer->green[4] = COLOR_MAX-1; lpBuffer->blue[4] = 0;
lpBuffer->red[5] = 0; lpBuffer->green[5] = COLOR_MAX-1; lpBuffer->blue[5] = COLOR_MAX-1;
lpBuffer->red[6] = COLOR_MAX-1; lpBuffer->green[6] = 0; lpBuffer->blue[6] = COLOR_MAX-1;
lpBuffer->red[7] = COLOR_MAX-1; lpBuffer->green[7] = COLOR_MAX-1; lpBuffer->blue[7] = COLOR_MAX-1;
for(r=0; r<COLOR_MAX; r++)
{
for(g=0; g<COLOR_MAX; g++)
for(b=0; b<COLOR_MAX; b++)
{
index = INDEX(r,g,b);
if(index == index_cache)
ptr = ptr_cache;
else
{
ptr = lpBuffer->lpHisto[index];
ptr_cache = ptr;
index_cache = index;
}
if(ptr != NULL)
{
if(ptr->count > pal[255])
{
pal[255] = ptr->count;
lpBuffer->red[255] = r;
lpBuffer->green[255] = g;
lpBuffer->blue[255] = b;
i = 255; /* bubble up */
while(pal[i]>pal[i-1] && i>8)
{
SWAP(pal[i], pal[i-1]);
SWAP(lpBuffer->red[i], lpBuffer->red[i-1]);
SWAP(lpBuffer->green[i], lpBuffer->green[i-1]);
SWAP(lpBuffer->blue[i], lpBuffer->blue[i-1]);
i--;
}
}
} /* end of current chain */
} /* end of r loop */
}
for(i=0; i<256; i++)
{
lpBuffer->red[i] *= 255;
lpBuffer->red[i] /= (COLOR_MAX-1);
lpBuffer->green[i] *= 255;
lpBuffer->green[i] /= (COLOR_MAX-1);
lpBuffer->blue[i] *= 255;
lpBuffer->blue[i] /= (COLOR_MAX-1);
}
} /* end of pop */
///////////////////////////////////////////////////////////////////////////
//
LPSTR AllocNewDIB(LPSTR lpDIB,LPQUANT_BUFFER lpBuffer)
{
long width,height;
LPBITMAPINFOHEADER lpbmih;
LPBITMAPINFO lpbmi;
long i;
long dest_dib_width;
LPSTR lpNewDIB;
DWORD dwSize;
if(!lpDIB)
return NULL;
lpbmih = (LPBITMAPINFOHEADER)lpDIB;
if(lpbmih->biBitCount != 24)
return NULL;
width = lpbmih->biWidth;
height = lpbmih->biHeight;
dest_dib_width = WIDTHBYTES(8*width);
dwSize = dest_dib_width*height + ((long)sizeof(BITMAPINFOHEADER) +
(long)(256 * sizeof(RGBQUAD)));
lpNewDIB = (LPSTR)GlobalAllocPtr(GHND | GMEM_SHARE,dwSize);
if(!lpNewDIB)
return NULL;
lpbmih = (LPBITMAPINFOHEADER)lpNewDIB;
lpbmih->biSize = sizeof(BITMAPINFOHEADER);
lpbmih->biWidth = (DWORD)width;
lpbmih->biHeight = (DWORD)height;
lpbmih->biPlanes = 1;
lpbmih->biBitCount = 8;
lpbmih->biCompression = BI_RGB;
lpbmih->biSizeImage = (DWORD)dwSize;
lpbmih->biClrUsed = 256;
lpbmih->biClrImportant = 256;
lpbmi = (LPBITMAPINFO)lpNewDIB;
for(i=0;i<256;i++)
{
lpbmi->bmiColors[i].rgbBlue = (BYTE)(lpBuffer->blue[i]);
lpbmi->bmiColors[i].rgbGreen = (BYTE)(lpBuffer->green[i]);
lpbmi->bmiColors[i].rgbRed = (BYTE)(lpBuffer->red[i]);
lpbmi->bmiColors[i].rgbReserved = (BYTE)0;
}
return lpNewDIB;
}
///////////////////////////////////////////////////////////////////////////
//
int GetNeighbor(int r,int g,int b,LPQUANT_BUFFER lpBuffer)
{
int bReturn;
DWORD index = 0;
long min_dist = 0;
long dist = 0;
int c;
int dr,dg,db;
int i,j,k;
LPNode ptr;
index = INDEX((r>>3),(g>>3),(b>>3));
if( (ptr = lpBuffer->lpHisto[index]) == NULL)
{
lpBuffer->lpHisto[index] = ptr = (Node *)malloc(sizeof(Node));
ptr->count = 0L;
ptr->index = -1;
}
if( (bReturn = ptr->index) == -1)
{
ptr->index = 0;
i = lpBuffer->red[0];
j = lpBuffer->green[0];
k = lpBuffer->blue[0];
dr = i - r;
dg = j - g;
db = k - b;
min_dist = lpBuffer->SQR[abs(dr)] + lpBuffer->SQR[abs(dg)] + lpBuffer->SQR[abs(db)];
for(c = 1;c<256;c++)
{
i = lpBuffer->red[c];
j = lpBuffer->green[c];
k = lpBuffer->blue[c];
dr = i - r;
dg = j - g;
db = k - b;
dist = lpBuffer->SQR[abs(dr)] + lpBuffer->SQR[abs(dg)] + lpBuffer->SQR[abs(db)];
if(dist < min_dist)
{
ptr->index = c;
min_dist = dist;
}
}
bReturn = ptr->index;
}
return bReturn;
}
///////////////////////////////////////////////////////////////////////////
//
void __export jitter(long x, long y, int *r,int *g,int *b)
{
int p,q;
int tmp;
tmp = *r;
if(tmp < 248)
{
p = tmp & 7;
q = jitterx(x,y,0);
if(p <= q)
tmp += 8;
q = tmp + jittery(x,y,0);
if(q >= 0 && q <= 255)
tmp = q;
*r = tmp & 0xF8;
}
tmp = *g;
if(tmp < 248)
{
p = tmp & 7;
q = jitterx(x,y,1);
if(p <= q)
tmp += 8;
q = tmp + jittery(x,y,1);
if(q >= 0 && q <= 255)
tmp = q;
*g = tmp & 0xF8;
}
tmp = *b;
if(tmp < 248)
{
p = tmp & 7;
q = jitterx(x,y,2);
if(p <= q)
tmp += 8;
q = tmp + jittery(x,y,2);
if(q >= 0 && q <= 255)
tmp = q;
*b = tmp & 0xF8;
}
}
///////////////////////////////////////////////////////////////////////////
//
void __export LoadDefaultPal(LPQUANT_BUFFER lpBuffer)
{
int *ptr = def_pal;
int i;
for(i=0;i<256;i++)
{
lpBuffer->red[i] = *ptr++;
lpBuffer->green[i] = *ptr++;
lpBuffer->blue[i] = *ptr++;
}
}
///////////////////////////////////////////////////////////////////////////
//
LPSTR FAR FindDIBBits(LPSTR lpDIB)
{
return (lpDIB + *(LPDWORD)lpDIB + PaletteSize(lpDIB));
}
///////////////////////////////////////////////////////////////////////////
//
WORD FAR PaletteSize(LPSTR lpDIB)
{
/* calculate the size required by the palette */
if (IS_WIN30_DIB (lpDIB))
return (DIBNumColors(lpDIB) * sizeof(RGBQUAD));
else
return (DIBNumColors(lpDIB) * sizeof(RGBTRIPLE));
}
///////////////////////////////////////////////////////////////////////////
//
WORD FAR DIBNumColors(LPSTR lpDIB)
{
WORD wBitCount; // DIB bit count
/* If this is a Windows-style DIB, the number of colors in the
* color table can be less than the number of bits per pixel
* allows for (i.e. lpbi->biClrUsed can be set to some value).
* If this is the case, return the appropriate value.
*/
if (IS_WIN30_DIB(lpDIB))
{
DWORD dwClrUsed;
dwClrUsed = ((LPBITMAPINFOHEADER)lpDIB)->biClrUsed;
if (dwClrUsed)
return (WORD)dwClrUsed;
}
/* Calculate the number of colors in the color table based on
* the number of bits per pixel for the DIB.
*/
if (IS_WIN30_DIB(lpDIB))
wBitCount = ((LPBITMAPINFOHEADER)lpDIB)->biBitCount;
else
wBitCount = ((LPBITMAPCOREHEADER)lpDIB)->bcBitCount;
/* return number of colors based on bits per pixel */
switch (wBitCount)
{
case 1:
return 2;
case 4:
return 16;
case 8:
return 256;
default:
return 0;
}
}